package com.xk._04regEx;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @description: 分析Java的正则表达式的底层实现（Important）
 * @author: xu
 * @date: 2022/11/1 14:40
 */
public class RegTheory {
    public static void main(String[] args) {
        String content = "1998年12月8日，第二代Java平台的企业版J2EE发布。1999年6月，" +
                "Sun公司发布了第二代Java平台（简称为Java2）的3个版本：" +
                "J2ME（Java2 Micro Edition，Java2平台的微型版），应用于移动、无线及有限资源的环境；" +
                "J2SE（Java 2 Standard Edition，Java 2平台的标准版），应用于桌面环境；" +
                "J2EE（Java 2Enterprise Edition，Java 2平台的企业版），应用于基于Java的应用服务器。3443" +
                "Java 2平台的发布，是Java发展过程中最重要的一个里程碑，标志着Java的应用开始普及9889。\n" +
                "1999年4月27日，HotSpot虚拟机发布。HotSpot虚拟机发布时是作为JDK 1.2的附加程序提供的，" +
                "后来它成为了JDK 1.3及之后所有版本的Sun JDK的默认虚拟机 [11]。";
        // 目标：匹配所有四个数字
        // 说明：
        // 1. \\d 表示一个任意的数字
        String regStr = "(\\d\\d)(\\d\\d)";
        // 2. 创建模式对象[即正则表达式对象]
        Pattern pattern = Pattern.compile(regStr);
        // 3. 创建匹配器
        // 说明：创建匹配器 matcher，按照 正则表达式的规则 去匹配 content字符串
        Matcher matcher = pattern.matcher(content);
        // 4. 开始匹配
        while (matcher.find()) {
            /*
            * 小结：
            *   1. 如果正则表达式有() 即分组
            *   2. 取出匹配的字符串规则如下
            *   3. matcher.group(0) 表示匹配到的子字符串
            *   4. matcher.group(1) 表示匹配到的子字符串的第一组字串
            *   5. matcher.group(2) 表示匹配到的子字符串的第二组字串
            *   6. ... 但是分组的数不能越界
            * */
            System.out.println("找到：" + matcher.group(0));
            System.out.println("第一组()匹配到的值：" + matcher.group(1));
            System.out.println("第二组()匹配到的值：" + matcher.group(2));
        }

        /*
        * matcher.find() 完成的任务(不考虑分组)
        *   1.根据指定的规则，定位满足规则的子字符串(比如1998)
        *   2.找到后，将 子字符串 开始的索引记录到 matcher对象的属性 int[] groups;
        *     groups[0] = 0，把该子字符串的结束的索引+1的值记录到 groups[1] = 4
        *   3.同时记录 oldLast 的值为 子字符串的结束的索引+1 的值即4，即下次执行find时，就从4开始匹配
        *
        * matcher.group(0) 分析
        * 源码：
        * public String group(int group) {
        *     if (first < 0)
        *         throw new IllegalStateException("No match found");
        *     if (group < 0 || group > groupCount())
        *         throw new IndexOutOfBoundsException("No group " + group);
        *     if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
        *         return null;
        *     return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
        * }
        * 1. 根据 group[0]=0 和 group[1]=4 的记录的位置，从content开始截取子字符串返回
        *    就是 [0, 4) 包含 0 但是不包含 4 的位置(左闭右开)
        *
        * 如果再次执行 find 方法，仍然按照上面的分析来执行
        * */

        /*
         * matcher.find() 完成的任务(考虑分组)
         * 什么是分组，比如 (\\d\\d)(\\d\\d)，正则表达式中有() 表示分组，第一个()表示第一组，第二个()表示第二组...
         *   1.根据指定的规则，定位满足规则的子字符串( 比如(19)(98) )
         *   2.找到后，将 子字符串 开始的索引记录到 matcher对象的属性 int[] groups;
         *     2.1 groups[0] = 0，把该子字符串的结束的索引+1的值记录到 groups[1] = 4
         *     2.2 记录第一组()匹配到的字符串 groups[2] = 0，groups[3] = 2
         *     2.3 记录第二组()匹配到的字符串 groups[4] = 2，groups[5] = 4
         *     2.4 如果有更多的分组...
         *   3.同时记录 oldLast 的值为 子字符串的结束的索引+1 的值即4，即下次执行find时，就从4开始匹配
         *
         * matcher.group(0) 分析
         * 源码：
         * public String group(int group) {
         *     if (first < 0)
         *         throw new IllegalStateException("No match found");
         *     if (group < 0 || group > groupCount())
         *         throw new IndexOutOfBoundsException("No group " + group);
         *     if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
         *         return null;
         *     return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
         * }
         * 1. 根据 group[0]=0 和 group[1]=4 的记录的位置，从content开始截取子字符串返回
         *    就是 [0, 4) 包含 0 但是不包含 4 的位置(左闭右开)
         *
         * 如果再次执行 find 方法，仍然按照上面的分析来执行
         * */
    }
}
